package gitobject;



import sha1.SHA1;

import stage.IndexElement;
import zlib.ZLibUtils;
import fileoperation.FileReader;

import java.io.*;
import java.lang.reflect.Array;
import java.security.MessageDigest;
import java.util.*;



public class Tree extends GitObject{
    protected ArrayList<GitObject> treeList;    //GitObjects in tree

    public ArrayList<GitObject> getTreeList(){
        return treeList;
    }

    public Tree(){}
    
    /**
     * Constructor
     * @param file
     * @throws Exception
     */
    public Tree(File file) throws Exception {
        this.treeList = new ArrayList<>();
        this.fmt = "tree";
        this.mode = "040000";
        this.value = "";
        genKey(file);
//        compressWrite();
        writeObject();
    }

    public Tree(HashMap<String, IndexElement> indexTree) throws Exception {
        this.treeList = new ArrayList<>();
        this.fmt = "tree";
        this.mode = "040000";
        this.value = "";
        genKey(indexTree);
        writeObject();
    }

    /**
     * Deserialize a tree object with treeId and its path.
     * @param Id
     * @param Id
     * @throws IOException
     */
    public static Tree deserialize(String Id)  {
        String absPath = path + File.separator + Id.substring(0,2) + File.separator + Id.substring(2);
        Tree t = new Tree();
        try{
            /**
             * Todo: Add your code here.
             */
            ObjectInputStream os = new ObjectInputStream(new FileInputStream(absPath));
            t = (Tree)os.readObject();
//            System.out.println(t.value);
            os.close();
        }catch (Exception e){
            e.printStackTrace();
        }
        /* Todo: You should delete the return statement before you start. */
        return t;
    }


    /**
     * Sort the files in a certain order. You should consider whether it's a file or a directory.
     * @param fs
     * @return List
     */
    public List sortFile(File[] fs){
        List fileList = Arrays.asList(fs);
        Collections.sort(fileList, new Comparator<File>() {
            @Override
            // sort by name, folders always before files
            public int compare(File o1, File o2) {
                boolean l1 = o1.isDirectory();
                boolean l2 = o2.isDirectory();
                if(l1 && !l2) return -1;
                if(!l1 && l2) return 1;
                else return (o1.getName()).compareTo(o2.getName());
            }
        });

//        // sort by file size：
//        Collections.sort(fileList, new Comparator<File>() {
//            @Override
//            public int compare(File o1, File o2) {
//                return (int) (o1.length() - o2.length());
//            }
//        });
        return fileList;
    }

    /**
     * Generate the key of a tree object.
     * @param dir
     * @return String
     * @throws Exception
     */
    public String genKey(File dir) throws Exception{
        /* Todo: Add your code here. */
        String key = "";
        String blob_s = "";
        String tree_s = "";
        try{
            File[] fs = dir.listFiles();
            List<File> ls = sortFile(fs);
            int length = ls.size();
            //System.out.println(length);
            if (length != 0) {
                for (int i = 0; i < length; i++) {
                    //String newPath = ls.get(i).toString();
                    if (ls.get(i).isFile()) {
                        try {
                            blob_s += "100644 blob " + SHA1.getHash(ls.get(i)) + " " + ls.get(i).getName() + "\n";
                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                    } else if (ls.get(i).isDirectory()) {
                        tree_s += "040000 tree " + genKey(ls.get(i)) + " " + ls.get(i).getName();
                    }
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        this.value = blob_s + tree_s;
        key = SHA1.getHash(this.value);
        this.key = key;
        return key;
    }

    public String genKey(HashMap<String, IndexElement> IndexTree) throws Exception {
        for(Map.Entry<String, IndexElement> entry: IndexTree.entrySet() ){
            if(entry.getValue().indexTree != null){   //is dir
                Tree tree = new Tree(entry.getValue().indexTree);
                //treeList.add(tree);
                tree.writeObject();

                value += "040000 tree " + tree.getKey() + " " + entry.getKey() + "\n";
            } else{                                   //is file
                //Blob blob = new Blob(entry.getValue().blobID);
                value += "100644 blob " + entry.getValue().blobID + " " + entry.getKey() + "\n";

            }
        }
        key = SHA1.getHash(value);
        return key;
    }



    @Override
    public String toString(){
        return "040000 tree " + key;
    }



}



